using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Ink;
using System.Windows;
using System.Xml.Serialization;

using WozLib.UI.Ink;
using System.Diagnostics;
using WozLib.UI.Ink.SketchObjects;

namespace WozLib.UI.Ink.SketchCommands
{
  public class MoveBackwardSketchCommand : SketchCommand
  {

    [XmlElement("PreviousOrderWozObjects")]
    public List<SketchObject> PreviousOrderWozObjects
    {
      get
      {
        return _PreviousOrderWozObjects;
      }
      set
      {
        _PreviousOrderWozObjects = new List<SketchObject>(value);
      }
    } private List<SketchObject> _PreviousOrderWozObjects;

    public MoveBackwardSketchCommand()
    {
    }

    public MoveBackwardSketchCommand(IEnumerable<SketchObject> targetWozObjects,
      IEnumerable<SketchObject> previousOrderWozObjects)
      : base(targetWozObjects)
    {
      PreviousOrderWozObjects = new List<SketchObject>(previousOrderWozObjects);
    }

    public override void Redo()
    {
      if (this.TargetWozObjects != null && this.WozClientCommandReferences != null && this.WozClientCommandReferences.InkCanvas != null)
      {
        StrokeCollection selectedStrokes = new StrokeCollection();
        List<UIElement> selectedUies = new List<UIElement>();

        SketchInkCanvas woc = this.WozClientCommandReferences.InkCanvas;

        foreach (SketchObject wozObject in this.TargetWozObjects)
        {
          ISketchObject iWozObject = wozObject.GetIWozObject(this.WozClientCommandReferences.WozObjectRegistry);
          if (iWozObject is Stroke)
          {
            selectedStrokes.Add(iWozObject as Stroke);
          }
          else if (iWozObject is UIElement)
          {
            selectedUies.Add(iWozObject as UIElement);
          }
        }

        // NOT THREAD SAFE
        for (int i = 1; i < woc.Children.Count; i++)
        {
          if (selectedUies.Contains(woc.Children[i]))
          {
            UIElement toMove = woc.Children[i];
            woc.Children.RemoveAt(i);
            woc.Children.Insert(i - 1, toMove);
          }
        }

        for (int i = 1; i < woc.Strokes.Count; i++)
        {
          if (selectedStrokes.Contains(woc.Strokes[i]))
          {
            Stroke toMove = woc.Strokes[i];
            woc.Strokes.RemoveAt(i);
            woc.Strokes.Insert(i - 1, toMove);
          }
        }

        woc.Select(selectedStrokes, selectedUies);
      }
    }

    public override void Undo()
    {
      try
      {
        if (this.TargetWozObjects != null && this.PreviousOrderWozObjects != null && this.WozClientCommandReferences != null && this.WozClientCommandReferences.InkCanvas != null)
        {
          StrokeCollection selectedStrokes = new StrokeCollection();
          List<UIElement> selectedUies = new List<UIElement>();

          SketchInkCanvas woc = this.WozClientCommandReferences.InkCanvas;

          foreach (SketchObject wozObject in this.TargetWozObjects)
          {
            ISketchObject iWozObject = wozObject.GetIWozObject(this.WozClientCommandReferences.WozObjectRegistry);
            if (iWozObject is Stroke)
            {
              selectedStrokes.Add(iWozObject as Stroke);
            }
            else if (iWozObject is UIElement)
            {
              selectedUies.Add(iWozObject as UIElement);
            }
          }

          woc.Children.Clear();
          woc.Strokes.Clear();

          foreach (SketchObject wozObject in this.PreviousOrderWozObjects)
          {
            ISketchObject iWozObject = wozObject.GetIWozObject(this.WozClientCommandReferences.WozObjectRegistry);
            if (iWozObject is Stroke)
            {
              woc.Strokes.Add(iWozObject as Stroke);
            }
            else if (iWozObject is UIElement)
            {
              woc.Children.Add(iWozObject as UIElement);
            }
          }

          woc.Select(selectedStrokes, selectedUies);
        }
      }
      catch (Exception ex)
      {
        Debug.WriteLine(ex.ToString());
      }
    }

  }
}
